#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "gr.h"

#define	STEP	20

struct gramaticaCDT{
	char * nombre;
	char * snt;
	char * st;
	char ini;
	struct produccionCDT ** prods;
	int numberOfProds;
	int size;
	int ea; 
};

struct produccionCDT{
	char * izq;
	char * derivaEn;
};

grADT newGr(void){
	grADT gr;
	gr = malloc(sizeof(struct gramaticaCDT));
	gr->nombre = NULL;
	gr->st = gr->snt = NULL;
	gr->prods = NULL;
	gr->numberOfProds = gr->size = 0;
	return gr;
}

char * getGrNombre(grADT gr){
	if(gr->nombre == NULL)
		return NULL;
		
	char * new;
	new = (char*)malloc(strlen(gr->nombre)+1);
	strcpy(new,gr->nombre);
	return new;
} 

void setGrNombre(grADT gr, char * str){
	int len;
	if(gr->nombre == NULL) {
		len = 0;
		gr->nombre = calloc(1, strlen(str)+1);
	} else {
		len = strlen(gr->nombre);
		gr->nombre= realloc(gr->nombre,strlen(str)+len+1);
	}
	strcat(gr->nombre,str);
	return;
}

void freeGr(grADT gr){
	int n = gr->numberOfProds, i;
	if(gr->nombre !=NULL)
		free(gr->nombre);
	for (i = 0; i < n; i++) {
		free(gr->prods[i]);
	}
	free(gr->prods);
	if (gr->snt != NULL) {
		free(gr->snt);
	}
	if (gr->st != NULL) {
		free(gr->st);
	}
	free(gr);
	return;	
}

void setGrNum(grADT gr, int ea){
	gr->ea=ea;
}

int getGrNum(grADT gr){
	return gr->ea;
}

prodADT newProd(void){
	prodADT new;
	new = malloc(sizeof(struct produccionCDT));
	new->izq = NULL;
	new->derivaEn = NULL;
	return new;
}

void freeProd(prodADT prod){
	if (prod->izq != NULL) {
		free(prod->izq);
	}
	if (prod->derivaEn != NULL) {
		free(prod->derivaEn);
	}
	free(prod);
}

void addProdIzq(prodADT prod, char * str){
	if (prod->izq == NULL) {
		prod->izq = calloc(1, strlen(str)+1);
	} else {
		prod->izq = realloc(prod->izq, strlen(str)+1);
	}
	if (prod->izq != NULL) {
		strcat(prod->izq, str);
	}
}

void addProdDer(prodADT prod, char * str){
	/* Voy agregando las derivaciones de a una. Supongo que se llamo previamente a setProdDerPipe para colocar el pipe */
	if (prod->derivaEn == NULL) {
		prod->derivaEn = calloc(1, strlen(str)+1);
	} else {
		prod->derivaEn = realloc(prod->derivaEn, strlen(str));
	}
	if (prod->derivaEn != NULL) {
		strcat(prod->derivaEn, str);
	}
}

void setProdDerPipe(prodADT prod){
	/* Agrego espacio para colocar el pipe */
	prod->derivaEn = realloc(prod->derivaEn, 1);
	if (prod->derivaEn != NULL) {
		strcat(prod->derivaEn, "|");
	}
}

void saveGrProd(grADT gr,prodADT prod){
	if (gr->size == gr->numberOfProds) {
		gr->size += STEP;
		gr->prods = realloc(gr->prods, gr->size);
	}
	gr->prods[gr->numberOfProds] = malloc(sizeof(struct produccionCDT));
	if (gr->prods[gr->numberOfProds] != NULL) {
		gr->prods[gr->numberOfProds]->izq = malloc(strlen(prod->izq)+1);
		strcpy(gr->prods[gr->numberOfProds]->izq, prod->izq);
		gr->prods[gr->numberOfProds]->derivaEn = malloc(strlen(prod->derivaEn)+1);
		strcpy(gr->prods[gr->numberOfProds]->derivaEn, prod->derivaEn);
		gr->numberOfProds++;
	}
}

void printProds (grADT gr) {
	int n = gr->numberOfProds, i;
	for (i = 0; i < n; i++) {
		printf("\t\t%s->%s\n", gr->prods[i]->izq, gr->prods[i]->derivaEn);
	}
}

void addGrSNT(grADT gr, char c){
	int len;
	char * str = calloc(1,2);
	str[0]=c;
	
	if(gr->snt == NULL) {
		len = 0;
		gr->snt= calloc(1,strlen(str)+1);
	} else {
		len = strlen(gr->snt);
		gr->snt= realloc(gr->snt,strlen(str)+len+1);
	}
	strcat(gr->snt,str);
	free (str);
	return;
}

void addGrST(grADT gr, char c){
	int len;
	char * str = calloc(1,2);
	str[0]=c;
	
	if(gr->st == NULL) {
		len = 0;
		gr->st= calloc(1,strlen(str)+1);
	} else {
		len = strlen(gr->st);
		gr->st= realloc(gr->st,strlen(str)+len+1);
	}
	strcat(gr->st,str);
	free (str);
	return;
}

char * getGrSNT(grADT gr){
	if(gr->snt == NULL)
		return NULL;
		
	char * new;
	new = (char*)malloc(strlen(gr->snt)+1);
	strcpy(new,gr->snt);
	return new;  
}

char * getGrST(grADT gr){
	if(gr->st == NULL)
		return NULL;
		
	char * new;
	new = (char*)malloc(strlen(gr->st)+1);
	strcpy(new,gr->st);
	return new;  
}

char ** getGrProd(grADT gr) {
	int n = gr->numberOfProds, i;
	char ** prods = malloc((n+1) * sizeof(char*));	
	if (gr->prods == NULL) {
		return NULL;
	}
	for (i = 0; i < n; i++) {
		prods[i] = malloc(strlen(gr->prods[i]->izq)+2+strlen(gr->prods[i]->derivaEn)+1);
		if (prods[i] != NULL) {
			strcpy(prods[i], gr->prods[i]->izq);
			strcat(prods[i], "->");
			strcat(prods[i], gr->prods[i]->derivaEn);
		}
	}
	prods[n] = NULL;
	return prods;	
}

